package net.openadventure;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.util.Vector;

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.event.MouseInputListener;

public class ForegroundCanvas {

	private static final long serialVersionUID = 1L;

	// The list of all items drawn on the screen
	private Vector<ScreenElement> elements = new Vector<ScreenElement>();

	private JPanel panel;
	
	// FPS variables
	private boolean displayFPS = true;

	private long lastTime = System.currentTimeMillis();

	private long slowDownTimer = lastTime;

	private int lastRecordedFPS = 0;

	// Mouse states
	private MouseButtonState mouseState = MouseButtonState.MOUSE_CLEAR;

	// Last mouse action coordinates
	private int lastMouseActionCoordinateX = -1;
	private int lastMouseActionCoordinateY = -1;

	private int resolutionWidth;
	private int resolutionHeight;

	public ForegroundCanvas(int resolutionWidth, int resolutionHeight) {
        panel = new FCJPanel(true);
        
        panel.setPreferredSize(new Dimension(resolutionWidth, resolutionHeight));

		this.resolutionWidth = resolutionWidth;
		this.resolutionHeight = resolutionHeight;
	}

	public MouseButtonState update(Vector<ScreenElement> elements) {
		MouseButtonState oldMouseState = mouseState;
		switch (mouseState) {
		case MOUSE_CLEAR:
			this.elements = elements;
			panel.repaint();
			break;
		case MOUSE_DOWN:
			this.elements = elements;
			panel.repaint();
			break;
		case MOUSE_RELEASED:
			mouseState = MouseButtonState.MOUSE_CLEAR;
			break;
		default:
			break;
		}
		return oldMouseState;
	}

	/**
	 * Sets whether or not to display the frames per second
	 * 
	 * @param displayFPS
	 *            A boolean indicating whether or not to display FPS
	 */
	public void setDisplayFPS(boolean displayFPS) {
		this.displayFPS = displayFPS;
	}

	/**
	 * Returns the translated x coordinate of the last mouse action
	 * 
	 * @return The x coordinate
	 */
	public int getMouseCoordinateX() {
		// Calculate the resolution translation
		double widthAdjustment = panel.getSize().getWidth() / resolutionWidth;
		return (int) (lastMouseActionCoordinateX / widthAdjustment);
	}

	/**
	 * Returns the translated y coordinate of the last mouse action
	 * 
	 * @return The y coordinate
	 */
	public int getMouseCoordinateY() {
		// Calculate the resolution translation
		double heightAdjustment = panel.getSize().getHeight() / resolutionHeight;
		return (int) (lastMouseActionCoordinateY / heightAdjustment);
	}
	
	public void setResolution(int resolutionWidth, int resolutionHeight) {
		this.resolutionWidth = resolutionWidth;
		this.resolutionHeight = resolutionHeight;
	}

	public int getResolutionWidth() {
		return resolutionWidth;
	}

	public int getResolutionHeight() {
		return resolutionHeight;
	}
	
    public JComponent getJPanel() {
        return panel;
    }

    private class FCJPanel extends JPanel implements MouseInputListener {

		private static final long serialVersionUID = -3080657377402598955L;

		public FCJPanel(boolean arg0) {
            super(arg0);
            
    		// Connect the mouse input listeners
    		addMouseListener(this);
    		addMouseMotionListener(this);
    		
    		setOpaque(false);
        }

    	/**
    	 * The overridden method to control painting of all the sprites on the
    	 * screen
    	 */
    	protected void paintComponent(Graphics g) {
    		super.paintComponent(g);

    		// Convert Graphics to Graphics2D for added functionality.
    		Graphics2D g2 = (Graphics2D) g;

    		// Calculate the resolution translation
    		double widthAdjustment = getSize().getWidth() / resolutionWidth;
    		double heightAdjustment = getSize().getHeight() / resolutionHeight;

    		// Draw each component
    		for (int c = 0; c < elements.size(); c++) {
    			ScreenElement currentSprite = elements.get(c);

    			g2.drawImage(currentSprite.getImage(),
    					(int) (currentSprite.getX() * widthAdjustment),
    					(int) (currentSprite.getY() * heightAdjustment),
    					(int) (currentSprite.getImage().getWidth(null) * widthAdjustment),
    					(int) (currentSprite.getImage().getHeight(null) * heightAdjustment), this);
    		}

    		// This section handles displaying the frames per second in the upper
    		// left hand corner.
    		if (displayFPS) {
    			// Calculate the FPS
    			try {
    				int tempFPS = (int) (1000 / (System.currentTimeMillis() - lastTime));
    				// slows down the refresh rate of the FPS number
    				if (System.currentTimeMillis() - slowDownTimer > 1000) {
    					lastRecordedFPS = tempFPS;
    					slowDownTimer = System.currentTimeMillis();
    				}
    			} catch (ArithmeticException e) {
    			}
    			lastTime = System.currentTimeMillis();

    			// Draw the background box
    			g2.setColor(Color.black);
    			g2.fillRect(0, 0, 90, 25);

    			// Display the FPS
    			g2.setColor(Color.red);
    			g2.setFont(Font.decode("ariel-bold-20"));
    			g2.drawString(" FPS: " + lastRecordedFPS, 0, 20);
    		}
    	}

    	public void mouseClicked(MouseEvent e) {
    	}

    	public void mouseDragged(MouseEvent e) {
    		lastMouseActionCoordinateX = e.getX();
    		lastMouseActionCoordinateY = e.getY();
    	}

    	public void mouseEntered(MouseEvent e) {
    	}

    	public void mouseExited(MouseEvent e) {
    	}

    	public void mouseMoved(MouseEvent e) {
    		lastMouseActionCoordinateX = e.getX();
    		lastMouseActionCoordinateY = e.getY();
    	}

    	public void mousePressed(MouseEvent e) {
    		lastMouseActionCoordinateX = e.getX();
    		lastMouseActionCoordinateY = e.getY();
    		mouseState = MouseButtonState.MOUSE_DOWN;
    	}

    	public void mouseReleased(MouseEvent e) {
    		lastMouseActionCoordinateX = e.getX();
    		lastMouseActionCoordinateY = e.getY();
    		mouseState = MouseButtonState.MOUSE_RELEASED;
    	}
    }
}
